//------------------------------------------------------------------------------
// X2TK Graphic Toolkit
// Copyright (C) 2006-2008 Janusz Kowalski
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
//------------------------------------------------------------------------------

#include "x2tk.h"
#include "x2tk_Widget.h"
#include "global.h"
#include "x2d_ext.h"
#include "pmsg.h"

namespace x2tk {

void Widget::event(EV ev) {
  fEvFocus_=false;
  if(ev==EV_FOCUS) fEvFocus_=false;
}

bool Widget::hasFocus() {
  return (!!parent_ && parent_->getFocusOwner()==this && parent_->hasFocus());
}

void Widget::setFocus() {
  if(!!parent_) {
    parent_->setFocusOwner(this);
    parent_->setFocus();
  }
}

Widget *Widget::getFocusOwner() {
  return focusOwner_;
}

void Widget::setFocusOwner(Widget *newFocusOwner) {
  if(focusOwner_!=newFocusOwner) {
    Widget *oldFocusOwner=focusOwner_;
    focusOwner_=newFocusOwner;
    
    // Inform the branch of the new focus owner.
    while(!!newFocusOwner && !newFocusOwner->fEvFocus_) {
      newFocusOwner->fEvFocus_=true;
      pushEvent(newFocusOwner, EV_FOCUS);
      newFocusOwner=newFocusOwner->getFocusOwner();
    }

    // Inform the brach of the old focus owner.
    while(!!oldFocusOwner && !oldFocusOwner->fEvFocus_) {
      oldFocusOwner->fEvFocus_=true;
      pushEvent(oldFocusOwner, EV_FOCUS);
      oldFocusOwner=oldFocusOwner->getFocusOwner();
    }
  }
}

void Widget::setVisible(bool v) {
  // Hidden widget cannot have focus.
  if(!v && !!parent_ && parent_->getFocusOwner()==this) {
    parent_->setFocusOwner(0);
  }
  visible=v;
}


void Widget::move_(Widget *w, bool top) {
  // Find the new position.
  unsigned i;
  if(top) {
    for(i=0; i<children.size(); i++) {
      if(children[i]->level_ > w->level_) break;
    }
  } else {
    for(i=children.size(); i--;) {
      if(children[i]->level_ < w->level_) break;
    }
    i+=1;
  }
  // Find the old position.
  unsigned j = children.indexOf__(w); ASSURE(j<children.size());
  if(j<i) i--;
  
  // Move.
  Widget *tmp = children[j];
  if(j<i) for(unsigned k=j; k<i; k++) children[k]=children[k+1];
  else for(unsigned k=j; k>i; k--) children[k]=children[k-1];
  children[i]=tmp;
}

void Widget::toTheTop() {
  parent_->move_(this, true);
}

void Widget::toTheBottom() {
  parent_->move_(this, false);
}

void Widget::add(Widget *child) {
  REQUIRE(this!=0); REQUIRE(child!=0); REQUIRE(!isDescendantOf(child));
  
  if(child->parent_==this) return;
  
  // First step - remove.
  if(child->parent_!=0) child->parent_->remove(this);
  
  // Second step - actual add.
  children.add(child);
  child->parent_=this;
  
  layout(); child->layout();
}

void Widget::remove(Widget *child) {
  REQUIRE(this!=0); REQUIRE(child!=0); REQUIRE(child->parent_==this);
  
  children.removeElement(child);
  child->parent_=0;
  if(focusOwner_==child) focusOwner_=0;
  
  layout();
}

Widget* Widget::NONE = 0;

Widget::Widget(int x, int y, int w, int h) : Rectangle (x,y,w,h) {
  visible=true;
  parent_=0;
  level_=0;
  focusOwner_=0;
  fEvFocus_=false;
}

Widget::~Widget() {
  // Cancel all timed calls to this widget.
  cancelCalls(this);
  // Tell your parent that you are leaving.
  if(parent_!=0) parent_->remove(this);
  for(int i=nChildren(); i--;) {
    delete children[i];
  }
}

Widget *Widget::getParent() {
  return parent_;
}

void Widget::action(int id, Widget *origin) {
  if(parent_!=0) parent_->action(id, origin);
}

short Widget::getMouseX() {
  if(parent_!=0) return parent_->getMouseX()-getX();
  else return -1;
}

short Widget::getMouseY() {
  if(parent_!=0) return parent_->getMouseY()-getY();
  else return -1; 
}

// By default, if the mouse was pressed inside the widget, we "wanted it".
bool Widget::mouseDown(int type) {
  if(getMouseX()<0) return false;
  if(!(getMouseX()<0+getW())) return false;
  if(getMouseY()<0) return false;
  if(!(getMouseY()<0+getH())) return false;
  setFocus();

  return true;
}

void Widget::event_key(const SDL_KeyboardEvent& key) {
  if(getFocusOwner()!=0) getFocusOwner()->event_key(key);
}

} // namespace x2d
